package fido.torrentsite;

import fido.FidoCommonUtils;
import fido.Torrent;
import fido.exceptions.IncorrectCookieException;
import fido.exceptions.NotConfiguredException;
import org.apache.log4j.Logger;
import org.mymediadb.api.mmdb.model.Movie;

import javax.swing.*;
import java.text.MessageFormat;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: Anders
 * Date: 09.06.11
 * Time: 01:24
 */
public abstract class CookiedTorrentSite implements TorrentSite {


    private String cookieString;
    private String searchUrl;

    protected static final Logger LOG = Logger.getLogger(TorrentLeech.class);

    private Pattern pattern;

    /**
     * @return A string which represents a row in a table in the HTML file, ie: <td class=detail align=center><p><a href='(http://www.bit-hdtv.com/download.php/.*?)'>.*?<a title=\"(.*?)\".*?href=\"(.*?)\">.*?<td class=detail align=center>.*?<td class=detail align=center>.*?<td class=detail align=center>(.*?)</td>.*?<span class=\"white\">(.*?)</span>
     */
    protected abstract String getRegex();

    /**
     * @return the url of the torrentSite, ie: http://www.bit-hdtv.com/
     */
    protected abstract String getURL();

    /**
     * @return the url for searching for torrents where {0} is replaced with the searchword
     */
    protected abstract String getSearchURL();

    /**
     * @param loginPageUrl the url of the page given after a login attempt.
     * @return true if logged in
     */
    protected abstract boolean isLoggedIn(String loginPageUrl);

    /**
     * used for FidoCommonUtils.prepareMovieNameForUrl
     *
     * @return ie. "ISO-8859-1", "UTF-8"
     */
    protected abstract String getTextEncoding();


    /**
     * @param matcher matchers to input in the search url
     * @param movie   the movie we are searching for
     * @return a torrent if torrent file is available.
     */
    protected abstract Torrent getTorrentFromMatcherData(Matcher matcher, Movie movie);


    /**
     * @return a map of the variables required to set up the cookies, where key is the actual name of the variable, and value is the key-alias to show when asking for the variable
     */
    protected abstract List<CookieVariable> getCookieVariables();


    public CookiedTorrentSite() {
        pattern = Pattern.compile(getRegex(), Pattern.DOTALL);

        FidoCommonUtils.loadAdditionalPropertiesFromFile(getTorrentSiteAlias());

        fetchRequiredProperties();
    }

    public final String getTorrentSiteAlias() {
        return getClass().getSimpleName();
    }

    protected final String getCookieString() {
        return cookieString;
    }

    private void fetchRequiredProperties() {
        searchUrl = FidoCommonUtils.getPropertyValue(getTorrentSiteAlias() + ".searchurl");
        cookieString = FidoCommonUtils.getPropertyValue(getTorrentSiteAlias() + ".cookies");
    }


    private boolean isCookiesValid(String newCookie) {
        return checkCookies(newCookie, null);
    }


    private boolean checkCookies(String cookie, String page) {
        if (page == null) {
            page = FidoCommonUtils.getWebPage(getURL(), cookie);
        }
        if (!isLoggedIn(page)) {
            LOG.debug(page);
            LOG.debug("Cookiestring for " + getTorrentSiteAlias() + " is '" + cookie + "'.");
            LOG.info("Authenticated failed on " + getTorrentSiteAlias() + ", check your '" + getTorrentSiteAlias() + ".cookies' property.");
            return false;
        }

        return true;
    }

    public final Torrent search(Movie movie) {
        if (!isConfigured()) {
            throw new NotConfiguredException("Not configured");
        }

        String movieName = FidoCommonUtils.prepareMovieNameForUrl(movie.getName(), getTextEncoding());
        String newSearch = MessageFormat.format(searchUrl, movieName);
        String page = FidoCommonUtils.getWebPage(newSearch, cookieString);

        if (!checkCookies(cookieString, page)) {
            throw new IncorrectCookieException("Incorrect cookie");
        }

        Matcher m = pattern.matcher(page);
        Torrent torrent = getTorrentFromMatcherData(m, movie);
        if (torrent != null) {
            torrent.setTorrentSiteName(this.getTorrentSiteAlias());
        }
        return torrent;

    }


    public final void configureWithGUI() {
        Properties propertiesTable = new Properties();
        //ask for cookie and save cookie to property
        String newCookie = "";
        JOptionPane.showMessageDialog(null, "You need to find you cookies for " + getTorrentSiteAlias() + ". Running " + getTorrentSiteAlias() + " configuration");

        newCookie = "";
        List<CookieVariable> cookieVariables = getCookieVariables();
        try {
            int cookieVariableCounter = 0;
            for (CookieVariable cookieVariable : cookieVariables) {
                cookieVariableCounter++;

                //add cookieVariable to newCookie string
                cookieVariable.setValue(JOptionPane.showInputDialog("Please enter your " + cookieVariable.getDisplayNameAndKey() + ":"));
                newCookie += cookieVariable.getVariableText();

                // add ";" between all variables.
                if (cookieVariableCounter != cookieVariables.size()) {
                    newCookie += "; ";
                }


            }
            if (isCookiesValid(newCookie)) {
                JOptionPane.showMessageDialog(null, "Connection to " + getTorrentSiteAlias() + " successful!");
                propertiesTable.setProperty(getTorrentSiteAlias() + ".cookies", newCookie);
                cookieString = newCookie;
                //save searchpath to property
                propertiesTable.setProperty(getTorrentSiteAlias() + ".searchurl", getSearchURL());
                // save this as a new settingsFile
                FidoCommonUtils.saveSettingsFile(getTorrentSiteAlias(), propertiesTable);

                FidoCommonUtils.loadAdditionalPropertiesFromFile(getTorrentSiteAlias());
                fetchRequiredProperties();
            } else {
                throw new NotConfiguredException("Invalid cookies");
            }
        } catch (IllegalArgumentException e) {
            JOptionPane.showMessageDialog(null, "Can't connect to " + getTorrentSiteAlias() + " due to 'configuration cancelled'.");
            throw new NotConfiguredException("Configuration cancelled by the user");
        } catch
                (Exception e) {
            JOptionPane.showMessageDialog(null, "Can't connect to " + getTorrentSiteAlias() + " due to '" + e.getMessage() + "'.");
            throw new NotConfiguredException("Could not configure");
        }
    }


    @Override
    public final void configureWithTUI() {
        LOG.info("Cant find all settings for " + getTorrentSiteAlias());
        LOG.info("Redirecting you to " + getTorrentSiteAlias() + " config");


        //This will install all settings needed for TorrentLeech
        //To its own settingsfile

        Properties properties = new Properties();

        String newCookie = "";
        List<CookieVariable> cookieVariables = getCookieVariables();
        do {
            LOG.info("");
            LOG.info("Please write you " + getTorrentSiteAlias() + " cookies here, You need to login on this workstation and get the cookies");
            int cookieVariableCounter = 0;
            for (CookieVariable cookieVariable : cookieVariables) {
                cookieVariableCounter++;

                LOG.info("Please enter your " + cookieVariable.getDisplayNameAndKey() + ":");
                cookieVariable.setValue(FidoCommonUtils.readKeyboardInput());

                //add cookieVariable to newCookie string
                newCookie += cookieVariable.getVariableText();

                // add ";" between all variables.
                if (cookieVariableCounter != cookieVariables.size()) {
                    newCookie += "; ";
                }
            }
            LOG.info("Checking you cookies, connecting to " + getTorrentSiteAlias() + " .. Please wait...");

        }
        while (!isCookiesValid(newCookie));
        LOG.info("");
        LOG.info("Connection to " + getTorrentSiteAlias() + " was successful!");
        properties.setProperty(getTorrentSiteAlias() + ".cookies", newCookie);
        cookieString = newCookie;


        //save searchpath to property
        properties.setProperty(getTorrentSiteAlias() + ".searchurl", getSearchURL());
        // save this as a new settingsFile
        FidoCommonUtils.saveSettingsFile(getTorrentSiteAlias(), properties);


        FidoCommonUtils.loadAdditionalPropertiesFromFile(getTorrentSiteAlias());
        //fetch new settings
        fetchRequiredProperties();
    }


    private boolean hasCookieString() {
        return (!cookieString.equals("") && cookieString != null);
    }

    private boolean hasSearchUrl() {
        return (!searchUrl.equals("") && searchUrl != null);
    }

    public final boolean isConfigured() {
        return (hasCookieString() && hasSearchUrl());
    }

    @Override
    public boolean equals(Object o) {
        if (o.getClass() != this.getClass()) {
            return false;
        }
        TorrentSite torrentSite = (TorrentSite) o;
        if (!torrentSite.getTorrentSiteAlias().equals(this.getTorrentSiteAlias())) {
            return false;
        }
        return true;
    }
}
